A ggplot2 demo

library(ggplot2)
library(grid)

dt <- data.frame( num = 1:10,
                  ab = rep(c("a", "b"), each = 5),
                  xy = rep(c("x", "y"), length.out = 10),
                  d = 1:10 / 10 )

p <- ggplot(dt, aes(x = num, y = num, fill = ab, color = xy, size = num, alpha = d)) + 
  facet_grid(ab ~ xy, scales = "free", switch = "both") + 
  geom_point()

p <- p + 
  guides(alpha = guide_legend(title = "Alpha"),
         size  = guide_legend(title = "Size"),
         color = guide_legend(title = "Color"),
         fill  = guide_legend(title = "Fill")
  ) +
  labs(title    = "title",
       subtitle = "subtitle",
       caption  = "caption",
#      tag      = "tag",
       x = "xlab.1",
       y = "ylab.1"
  ) +
  scale_x_continuous(sec.axis = dup_axis(name = "xlab.2")) +
  scale_y_continuous(sec.axis = dup_axis(name = "ylab.2"))

in debug style

p <- p +
  theme(
    legend.background = element_rect(fill = "grey", color = "black"),
    legend.box.background = element_rect(fill = "lightblue", color = "red"),
    legend.key   = element_rect(fill = "yellow", color = "green"),
    legend.text  = element_text(debug = TRUE),
    legend.title = element_text(debug = TRUE)
  ) +
  theme(
    axis.title = element_text(debug = TRUE),
    axis.text  = element_text(debug = TRUE),
    axis.line  = element_line(color = "red"),
  ) +
  theme(
    strip.text = element_text(debug = TRUE)
  ) +
  theme(
    plot.margin     = margin(0,0,0,0, "pt"),
    plot.background = element_rect(fill = "pink"),
    plot.title    = element_text(debug = TRUE, margin = margin(0,0,0,0, "line")),
    plot.subtitle = element_text(debug = TRUE, margin = margin(0,0,0,0, "line")),
    plot.caption  = element_text(debug = TRUE, margin = margin(0,0,0,0, "line")),
    plot.tag      = element_text(debug = TRUE)
  ) +
  theme(
    panel.background = element_rect(fill = "orange"),
  )

1 axis

1.1 axis.title

p + theme(
    axis.title          = element_text(size = 20, margin = margin(1,1,1,1,"line"))
#   axis.title.x        = element_text(),
#   axis.title.x.top    = element_text(),
#   axis.title.x.bottom = element_text(),
#   axis.title.y        = element_text(),
#   axis.title.y.left   = element_text(),
#   axis.title.y.right  = element_text(),
  )
  • you may find axis.title.*, axis.title.*.* do not inherit element_text(margin) from axis.title.
  • it’s because that in default theme, axis.title.x and axis.title.y have called element_text(margin) already
  • and which result in a gap between axis.title and axis.text in size unit(11 / 4, "pt").

 

p + theme(
#   axis.title          = element_text(),
    axis.title.x        = element_text(size = 20, margin = margin(1,1,1,1,"line")),
#   axis.title.x.top    = element_text(),
#   axis.title.x.bottom = element_text(),
    axis.title.y        = element_text(size = 20, margin = margin(1,1,1,1,"line"))
#   axis.title.y.left   = element_text(),
#   axis.title.y.right  = element_text(),
  )
  • also, you may find axis.title.x.top dose not inherit element_text(margin) from axis.title.x
  • and axis.title.y.right dose not inherit that from axis.title.y.

 

p + theme(
    axis.title          = element_text(size = 20),
    axis.title.x        = element_text(margin = margin(1,1,1,1,"line")),
    axis.title.x.top    = element_text(margin = margin(1,1,1,1,"line")),
#   axis.title.x.bottom = element_text(),
    axis.title.y        = element_text(margin = margin(1,1,1,1,"line")),
#   axis.title.y.left   = element_text(),
    axis.title.y.right  = element_text(margin = margin(1,1,1,1,"line"))
  )
  • so to change element_text(margin), these axis.title.** have to be set explicitly

 

1.2 axis.text

p + theme(
    axis.text = element_text(size = 20, margin = margin(1,1,1,1,"line"))
#   axis.text.x        = element_text(),
#   axis.text.x.top    = element_text(),
#   axis.text.x.bottom = element_text(),
#   axis.text.y        = element_text(),
#   axis.text.y.left   = element_text(),
#   axis.text.y.right  = element_text()
  )
  • same as axis.title

 

p + theme(
    axis.text = element_text(size = 20),
#   axis.text.x        = element_text(),
    axis.text.x.top    = element_text(vjust = 1),
    axis.text.x.bottom = element_text(vjust = 0),
#   axis.text.y        = element_text(),
    axis.text.y.left   = element_text(hjust = 0),
    axis.text.y.right  = element_text(hjust = 1)
  )
  • and there are also gaps between axis.text and axit.ticks, which due to default theme with default size unit(0.8 * 11 / 4, "pt").

 

1.3 axis.ticks

axis.ticks = element_line(size) only controls the length along axes, and does not effect the size of plot.

p + theme(
    axis.ticks = element_line(size = 10)
#   axis.ticks.x        = element_line(),
#   axis.ticks.x.top    = element_line(),
#   axis.ticks.x.bottom = element_line(),
#   axis.ticks.y        = element_line(),
#   axis.ticks.y.left   = element_line(),
#   axis.ticks.y.right  = element_line()
  )

 

p + theme(
    axis.ticks = element_line(size = 100)
#   axis.ticks.x        = element_line(),
#   axis.ticks.x.top    = element_line(),
#   axis.ticks.x.bottom = element_line(),
#   axis.ticks.y        = element_line(),
#   axis.ticks.y.left   = element_line(),
#   axis.ticks.y.right  = element_line()
  )

To control the length vertically, you need to change axis.ticks.length.

p + theme(
    axis.ticks.length = unit(0.5,"cm") # default unit(11 / 4, "pt")
#   axis.ticks.length.x        = NULL, 
#   axis.ticks.length.x.top    = NULL,
#   axis.ticks.length.x.bottom = NULL,
#   axis.ticks.length.y        = NULL,
#   axis.ticks.length.y.left   = NULL,
#   axis.ticks.length.y.right  = NULL
  )

 

1.4 axis.line

axis.line has no effect on plot size as well.

gt1 <- ggplotGrob(p)
gt1$heights
##  [1] 0pt                0cm                1grobheight        1grobheight       
##  [5] 1grobheight        0.46152783900704cm 1null              5.5pt             
##  [9] 1null              0.59683986336016cm 0.46152783900704cm 1grobheight       
## [13] 1grobheight        0pt                0pt
p2 <- p + theme(
    axis.line = element_line(size = 10, linetype = 'dashed')
#   axis.line.x        = element_line(),
#   axis.line.x.top    = element_line(),
#   axis.line.x.bottom = element_line(),
#   axis.line.y        = element_line(),
#   axis.line.y.left   = element_line(),
#   axis.line.y.right  = element_line()
  )
gt2 <- ggplotGrob(p2)
gt2$heights
##  [1] 0pt                0cm                1grobheight        1grobheight       
##  [5] 1grobheight        0.46152783900704cm 1null              5.5pt             
##  [9] 1null              0.59683986336016cm 0.46152783900704cm 1grobheight       
## [13] 1grobheight        0pt                0pt
p2

1.5 summary

2 strip

2.1 strip.text

p + theme(
    strip.text   = element_text(size = 20, margin = margin(1,1,1,1,"line")),
#   strip.text.x = element_text(),
#   strip.text.y = element_text()
  )

2.2 strip.switch.pad

strip.placement controls strips placing inside or outside axis.text grobs (including axis.text, axis.ticks and axis.line).

And strip.switch.pad.* only works for the outside strips, and controls the width of the gap between strips and axis.text grobs.

p + theme(strip.text = element_text(size = 20)) +
  theme(
#   strip.placement   = NULL,
    strip.placement.x = "outside",
    strip.placement.y = NULL
  ) +
  theme(
    strip.switch.pad.grid = unit(1, "line"),
#   strip.switch.pad.wrap = unit(1, "line") # for facet_wrap
  )

p + facet_wrap(ab ~ xy) +
  theme(strip.text = element_text(size = 20)) +
  theme(
    strip.placement = "outside",
    strip.switch.pad.wrap = unit(1, "line")
  )

ps. labeller(.multi_line) can collapse strips of the same side.

p + facet_wrap(ab ~ xy,
               labeller = labeller(.multi_line = F)) +
  theme(strip.text = element_text(size = 20)) +
  theme(
    strip.placement = "outside",
    strip.switch.pad.wrap = unit(1, "line")
  )

2.3 summary

3 panel

3.1 panel size

Unfortunately, unlike the elements mentioned above, the size of panels are not certain.

The unit of the viewport of the panels are 1NULL, which means the size of the panels only calculate after the plot is drawn.

They’re determined by the size of the window you open or the device you save graphics.

You cannot control the size of panels by setting theme.

gt <- ggplotGrob(p)
layout <- gtable:::gtable_layout(gt)
grid:::grid.show.layout(layout)

3.2 panel.spacing

But you can control the gap between each panels.

p + theme(
      panel.spacing = unit(1, "line"),
#     panel.spacing.x = NULL,
#     panel.spacing.y = NULL
    )

4 legend

4.1 legend.position

in character

Default legend.position is right, and also support left, top, bottom and none.

p + theme(legend.position = "left")

 

p + theme(legend.position = "top")

p + theme(legend.position = "bottom")

 

p + theme(legend.position = "none")

in numeric vector

legend.position also support a coordinate (two-element numeric vector).

A better practice is using in combination with legend.justification.

p + theme(
  legend.position = c(0.25, 0),
  legend.justification = c(0, 0) # default "center"
)

  • a simple illustration shows how it works :

But Comparing to the default layout (left), the legend will no longer be apart of the plot grob tree when using legend.position in this way. The legend will not contribute to panel calculation (see panel size).

 

4.2 legend.box & legend.box.just

legend.box controls the arrangement of multiple legends.

legend.box.just controls the justification of each legend within the overall bounding box, when there are multiple legends.

#default
p + theme(legend.box = "vertical", legend.box.just = "left")
p + theme(legend.box = "vertical", legend.box.just = "right")

p + theme(legend.box = "horizontal", legend.box.just = "top")

p + theme(legend.box = "horizontal", legend.box.just = "bottom")

4.3 legend.box.spacing

The spacing between the plotting area and the legend box.

See more example in legend.position, show how it effect in different conditions.

p + theme(legend.box.spacing = unit(2, "line"))
# default unit(11, "pt")

 

4.4 legend.box.margin

Margins around the full legend area.

p + theme(legend.box.margin  = margin(2,2,2,2, "line"))
# default margin(0, 0, 0, 0, "cm")

 

4.5 legend.margin

The margin around each legend.

p + theme(legend.margin = margin(2,2,2,2, "line"))
# default margin(5.5, 5.5, 5.5, 5.5, "pt")

 

4.6 legend.spacing

The spacing between legends.

legend.spacing.x controls the horizontal gaps between legend.title and legend.key, between legend.key and legend.text as well as between multi legends.

legend.spacing.y controls the vertical gaps between legend.title and legend.key, between legend.key and legend.text as well as between multi legends.

pl <- p + guides(
  size  = guide_legend(title = "Size",  ncol = 3, byrow = TRUE),
  alpha = guide_legend(title = "Alpha", ncol = 2)
)
pl + theme(
#   legend.spacing   = NULL, # default unit(11, "pt")
    legend.spacing.x = unit(1, "line"),
    legend.spacing.y = unit(2, "line")
  )

 

pl + theme(
    legend.spacing.x = unit(1, "line"),
    legend.spacing.y = unit(2, "line"),
    legend.box = "horizontal"
  )

4.7 legend.title & legend.text

p + theme(
  legend.title = element_text(size = 15, margin = margin(1,1,1,1, "line")),
  legend.text  = element_text(size = 15, margin = margin(1,1,1,1, "line"))
)

 

4.8 legend.key.size

legend.key.size controls the size of legend keys.

p + theme(
    legend.key.size = unit(3, "line") # default unit(1.2, "lines")
#   legend.key.height = NULL,
#   legend.key.width  = NULL
)

 

legend.key.size only effect the box of legend keys instead of the symbol. To resize the symbol inside legend keys, you need to use guides.

example

p + guides(alpha = guide_legend(title = "Alpha", override.aes = list(size = 20) ))

 

4.9 summary

5 plot

5.1 plot.margin

p + theme(plot.margin = margin(1,1,1,1, "line"))
# default margin(5.5, 5.5, 5.5, 5.5, "pt")

5.2 plot.title

p + theme(plot.title = element_text(margin = margin(1,1,1,1, "line"))) 
# default margin(b = 5.5, "pt")

5.3 plot.subtitle

p + theme(plot.subtitle = element_text(margin = margin(1,1,1,1, "line")))
# default margin(b = 5.5, "pt")

5.4 plot.caption

p + theme(plot.caption = element_text(margin = margin(1,1,1,1, "line")))
# default margin(t = 5.5, "pt")

5.5 plot.tag

p + labs(tag = "A")
# default margin(0, 0, 0, 0, "pt")

 

p + labs(tag = "A") + theme(plot.tag = element_text(margin = margin(1,1,1,1, "line")))

p + labs(tag = "A") +
  theme(legend.position = "left")

 

p + labs(tag = "A") +
  theme(legend.position = "top")

5.6 summary

Appendix

ggplot2 default themes

ggplot2::theme_grey

details

function (base_size = 11, base_family = "", base_line_size = base_size/22, 
    base_rect_size = base_size/22) 
{
    half_line <- base_size/2
    theme(line = element_line(colour = "black", size = base_line_size, 
        linetype = 1, lineend = "butt"), rect = element_rect(fill = "white", 
        colour = "black", size = base_rect_size, linetype = 1), 
        text = element_text(family = base_family, face = "plain", 
            colour = "black", size = base_size, lineheight = 0.9, 
            hjust = 0.5, vjust = 0.5, angle = 0, margin = margin(), 
            debug = FALSE), axis.line = element_blank(), axis.line.x = NULL, 
        axis.line.y = NULL, axis.text = element_text(size = rel(0.8), 
            colour = "grey30"), axis.text.x = element_text(margin = margin(t = 0.8 * 
            half_line/2), vjust = 1), axis.text.x.top = element_text(margin = margin(b = 0.8 * 
            half_line/2), vjust = 0), axis.text.y = element_text(margin = margin(r = 0.8 * 
            half_line/2), hjust = 1), axis.text.y.right = element_text(margin = margin(l = 0.8 * 
            half_line/2), hjust = 0), axis.ticks = element_line(colour = "grey20"), 
        axis.ticks.length = unit(half_line/2, "pt"), axis.ticks.length.x = NULL, 
        axis.ticks.length.x.top = NULL, axis.ticks.length.x.bottom = NULL, 
        axis.ticks.length.y = NULL, axis.ticks.length.y.left = NULL, 
        axis.ticks.length.y.right = NULL, axis.title.x = element_text(margin = margin(t = half_line/2), 
            vjust = 1), axis.title.x.top = element_text(margin = margin(b = half_line/2), 
            vjust = 0), axis.title.y = element_text(angle = 90, 
            margin = margin(r = half_line/2), vjust = 1), axis.title.y.right = element_text(angle = -90, 
            margin = margin(l = half_line/2), vjust = 0), legend.background = element_rect(colour = NA), 
        legend.spacing = unit(2 * half_line, "pt"), legend.spacing.x = NULL, 
        legend.spacing.y = NULL, legend.margin = margin(half_line, 
            half_line, half_line, half_line), legend.key = element_rect(fill = "grey95", 
            colour = "white"), legend.key.size = unit(1.2, "lines"), 
        legend.key.height = NULL, legend.key.width = NULL, legend.text = element_text(size = rel(0.8)), 
        legend.text.align = NULL, legend.title = element_text(hjust = 0), 
        legend.title.align = NULL, legend.position = "right", 
        legend.direction = NULL, legend.justification = "center", 
        legend.box = NULL, legend.box.margin = margin(0, 0, 0, 
            0, "cm"), legend.box.background = element_blank(), 
        legend.box.spacing = unit(2 * half_line, "pt"), panel.background = element_rect(fill = "grey92", 
            colour = NA), panel.border = element_blank(), panel.grid = element_line(colour = "white"), 
        panel.grid.minor = element_line(size = rel(0.5)), panel.spacing = unit(half_line, 
            "pt"), panel.spacing.x = NULL, panel.spacing.y = NULL, 
        panel.ontop = FALSE, strip.background = element_rect(fill = "grey85", 
            colour = NA), strip.text = element_text(colour = "grey10", 
            size = rel(0.8), margin = margin(0.8 * half_line, 
                0.8 * half_line, 0.8 * half_line, 0.8 * half_line)), 
        strip.text.x = NULL, strip.text.y = element_text(angle = -90), 
        strip.placement = "inside", strip.placement.x = NULL, 
        strip.placement.y = NULL, strip.switch.pad.grid = unit(half_line/2, 
            "pt"), strip.switch.pad.wrap = unit(half_line/2, 
            "pt"), plot.background = element_rect(colour = "white"), 
        plot.title = element_text(size = rel(1.2), hjust = 0, 
            vjust = 1, margin = margin(b = half_line)), plot.subtitle = element_text(hjust = 0, 
            vjust = 1, margin = margin(b = half_line)), plot.caption = element_text(size = rel(0.8), 
            hjust = 1, vjust = 1, margin = margin(t = half_line)), 
        plot.tag = element_text(size = rel(1.2), hjust = 0.5, 
            vjust = 0.5), plot.tag.position = "topleft", plot.margin = margin(half_line, 
            half_line, half_line, half_line), complete = TRUE)
}
<bytecode: 0x7fdfc8f10b88>
<environment: namespace:ggplot2>

session_info

devtools::session_info()

details

## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.6.1 (2019-07-05)
##  os       macOS Catalina 10.15.5      
##  system   x86_64, darwin15.6.0        
##  ui       X11                         
##  language (EN)                        
##  collate  en_US.UTF-8                 
##  ctype    en_US.UTF-8                 
##  tz       Asia/Shanghai               
##  date     2020-07-06                  
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package     * version date       lib source        
##  assertthat    0.2.1   2019-03-21 [1] CRAN (R 3.6.0)
##  backports     1.1.4   2019-04-10 [1] CRAN (R 3.6.0)
##  callr         3.3.2   2019-09-22 [1] CRAN (R 3.6.0)
##  cli           1.1.0   2019-03-19 [1] CRAN (R 3.6.0)
##  colorspace    1.4-1   2019-03-18 [1] CRAN (R 3.6.0)
##  crayon        1.3.4   2017-09-16 [1] CRAN (R 3.6.0)
##  desc          1.2.0   2018-05-01 [1] CRAN (R 3.6.0)
##  devtools      2.2.2   2020-02-17 [1] CRAN (R 3.6.0)
##  digest        0.6.20  2019-07-04 [1] CRAN (R 3.6.0)
##  dplyr         0.8.3   2019-07-04 [1] CRAN (R 3.6.0)
##  ellipsis      0.3.0   2019-09-20 [1] CRAN (R 3.6.0)
##  evaluate      0.14    2019-05-28 [1] CRAN (R 3.6.0)
##  fs            1.3.1   2019-05-06 [1] CRAN (R 3.6.0)
##  ggplot2     * 3.2.1   2019-08-10 [1] CRAN (R 3.6.0)
##  glue          1.3.1   2019-03-12 [1] CRAN (R 3.6.0)
##  gtable        0.3.0   2019-03-25 [1] CRAN (R 3.6.0)
##  htmltools     0.3.6   2017-04-28 [1] CRAN (R 3.6.0)
##  knitr         1.28    2020-02-06 [1] CRAN (R 3.6.0)
##  labeling      0.3     2014-08-23 [1] CRAN (R 3.6.0)
##  lazyeval      0.2.2   2019-03-15 [1] CRAN (R 3.6.0)
##  magick        2.3     2020-01-24 [1] CRAN (R 3.6.0)
##  magrittr      1.5     2014-11-22 [1] CRAN (R 3.6.0)
##  memoise       1.1.0   2017-04-21 [1] CRAN (R 3.6.0)
##  munsell       0.5.0   2018-06-12 [1] CRAN (R 3.6.0)
##  pillar        1.4.2   2019-06-29 [1] CRAN (R 3.6.0)
##  pkgbuild      1.0.6   2019-10-09 [1] CRAN (R 3.6.0)
##  pkgconfig     2.0.2   2018-08-16 [1] CRAN (R 3.6.0)
##  pkgload       1.0.2   2018-10-29 [1] CRAN (R 3.6.0)
##  plyr          1.8.4   2016-06-08 [1] CRAN (R 3.6.0)
##  png           0.1-7   2013-12-03 [1] CRAN (R 3.6.0)
##  prettyunits   1.0.2   2015-07-13 [1] CRAN (R 3.6.0)
##  processx      3.4.1   2019-07-18 [1] CRAN (R 3.6.0)
##  ps            1.3.0   2018-12-21 [1] CRAN (R 3.6.0)
##  purrr         0.3.3   2019-10-18 [1] CRAN (R 3.6.0)
##  R6            2.4.0   2019-02-14 [1] CRAN (R 3.6.0)
##  Rcpp          1.0.2   2019-07-25 [1] CRAN (R 3.6.0)
##  remotes       2.1.1   2020-02-15 [1] CRAN (R 3.6.0)
##  reshape2      1.4.3   2017-12-11 [1] CRAN (R 3.6.0)
##  rlang         0.4.5   2020-03-01 [1] CRAN (R 3.6.0)
##  rmarkdown     2.2     2020-05-31 [1] CRAN (R 3.6.1)
##  rprojroot     1.3-2   2018-01-03 [1] CRAN (R 3.6.0)
##  scales        1.0.0   2018-08-09 [1] CRAN (R 3.6.0)
##  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 3.6.0)
##  stringi       1.4.3   2019-03-12 [1] CRAN (R 3.6.0)
##  stringr       1.4.0   2019-02-10 [1] CRAN (R 3.6.0)
##  testthat      2.3.2   2020-03-02 [1] CRAN (R 3.6.0)
##  tibble        2.1.3   2019-06-06 [1] CRAN (R 3.6.0)
##  tidyselect    0.2.5   2018-10-11 [1] CRAN (R 3.6.0)
##  usethis       1.5.1   2019-07-04 [1] CRAN (R 3.6.0)
##  withr         2.1.2   2018-03-15 [1] CRAN (R 3.6.0)
##  xfun          0.10    2019-10-01 [1] CRAN (R 3.6.0)
##  yaml          2.2.0   2018-07-25 [1] CRAN (R 3.6.0)
## 
## [1] /Library/Frameworks/R.framework/Versions/3.6/Resources/library